package cn.edu.buaa.nlsde.mpj.fw.invoker.loader;

import cn.edu.buaa.nlsde.mpj.fw.model.input.Input;
import cn.edu.buaa.nlsde.mpj.fw.model.input.Inputs;
import cn.edu.buaa.nlsde.mpj.fw.model.output.Output;
import cn.edu.buaa.nlsde.mpj.fw.model.output.Outputs;
import cn.edu.buaa.nlsde.mpj.fw.model.parameter.LoopParameter;
import cn.edu.buaa.nlsde.mpj.fw.model.parameter.Parameter;
import cn.edu.buaa.nlsde.mpj.fw.model.parameter.Parameters;
import cn.edu.buaa.nlsde.mpj.fw.model.procedure.Procedures;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Iterator;
import java.util.List;

public class Loader {
    private static Log log = LogFactory.getLog(Loader.class);
    private String modelFileFolder;
    private String modelFileName;
    private Document document;

    //生成一个Document对象
    private Document createDocument() {
        Document doc = null;
        try {
            log.info("开始加载模型文件" + modelFileName + "。");
            URI uri = Thread.currentThread().getContextClassLoader()
                    .getResource(modelFileFolder + File.separator + modelFileName).toURI();
            log.info("模型文件" + modelFileName + "的路径-->" + uri);
            File modelFile = new File(uri);
            if (modelFile.exists()) {
                SAXReader sr = new SAXReader();
                doc = sr.read(modelFile);
                log.info("加载模型文件" + modelFile.getName() + "成功。");
            } else {
                log.error("找不到模型文件" + modelFileName);
            }
        } catch (NullPointerException e) {
            log.error("模型路径加载错误，请检查在ClassPath下是否有" + modelFileFolder + "文件夹，以及"
                    + modelFileFolder + "文件夹内是否有" + modelFileName + "文件。");
        } catch (URISyntaxException e) {
            log.error(e.getMessage());
        } catch (DocumentException e) {
            log.error(e.getMessage());
        }
        return doc;
    }

    //判断计算过程元素是否为空
    private boolean isLoopProcedure(Element element) {
        return element.element("loopby") != null;
    }

    //构造函数
    public Loader(String modelFileName, String modelFileFolder) {
        this.modelFileName = modelFileName;
        this.modelFileFolder = modelFileFolder;
        this.document = createDocument();
    }

    //获得模型名称
    public String getModelName() {
        return document.getRootElement().attributeValue("name");
    }

    //获得模型描述
    public String getModelDescription() {
        return document.getRootElement().attributeValue("desc");
    }

    //获取模型输入变量序列
    public Inputs getModelInputs() {
        Inputs inputs = new Inputs();
        List<Element> elements = document.selectNodes("model/inputs/input");
        if (elements.size() > 0) {
            Iterator<Element> iterator = elements.iterator();
            while (iterator.hasNext()) {
                InputResolver resolver = new InputResolver();
                Input input = resolver.resolve(iterator.next());
                log.info("解析模型输入变量" + input.getName() + "('" + input.getName() + "','"
                        + input.getType() + "','null')完毕。");
            }
        } else {
            log.warn("模型" + modelFileName + "没有输入变量。");
        }
        return inputs;
    }

    //将模型参数变量放入集合中
    private void putParameter(Parameters parameters) {
        List<Element> elements = document.selectNodes("model/parameters/parameter");
        if (elements.size() > 0) {
            Iterator<Element> iterator = elements.iterator();
            while (iterator.hasNext()) {
                ParameterResolver resolver = new ParameterResolver();
                Parameter parameter = resolver.resolve(iterator.next());
                parameters.put(parameter.getName(), parameter);
                log.info("解析模型参数变量" + parameter.getName() + "('" + parameter.getName()
                        + "','" + parameter.getType() + "','" + parameter.getValue() + "')完毕。");
            }
        } else {
            log.warn("模型" + modelFileName + "没有参数变量。");
        }
    }

    //将模型循环参数放入集合中
    private void putLoopParameter(Parameters parameters) {
        List<Element> elements = document.selectNodes("model/parameters/loop");
        if (elements.size() > 0) {
            Iterator<Element> iterator = elements.iterator();
            while (iterator.hasNext()) {
                LoopParameterResolver resolver = new LoopParameterResolver();
                LoopParameter loopParameter = resolver.resolve(iterator.next());
                log.info("解析模型参数循环变量" + loopParameter.getName()
                        + "('" + loopParameter.getName() + "','" + loopParameter.getType()
                        + "','" + loopParameter.getStart() + "','" + loopParameter.getEnd()
                        + "','" + loopParameter.getStep() + "')完毕。");
            }
        } else {
            log.info("模型" + modelFileName + "没有循环变量。");
        }

    }

    //获取模型参数序列
    public Parameters getModelParameters() {
        Parameters parameters = new Parameters();
        putParameter(parameters);
        putLoopParameter(parameters);
        return parameters;
    }

    //获取模型输出变量序列
    public Outputs getModelOutputs() {
        List<Element> elements = document.selectNodes("model/outputs/output");
        Outputs outputs = new Outputs();
        if (elements.size() > 0) {
            Iterator<Element> iterator = elements.iterator();
            while (iterator.hasNext()) {
                OutputResolver resolver = new OutputResolver();
                Output output = resolver.resolve(iterator.next());
                log.info("解析模型输出变量" + output.getName() + "('" + output.getName()
                        + "','" + output.getType() + "','null')");
            }
        }
        return outputs;
    }

    //获取模型处理过程对象
    public Procedures getModelProcedures() {
        List<Element> elements = document.selectNodes("model/procedures/procedure");
        Iterator<Element> iterator = elements.iterator();
        while (iterator.hasNext()) {
            if (isLoopProcedure(iterator.next())) {

            }
        }
        return null;
    }

}
